package bc.sistema.usuario.professor;

import bc.exceptions.RespostaInvalidaException;
import bc.exceptions.SalaInvalidaException;
import bc.exceptions.SenhaInvalidaException;
import bc.exceptions.StringVaziaException;
import bc.exceptions.TelefoneInvalidoException;
import bc.sistema.usuario.Telefone;
import bc.sistema.usuario.Usuario;
import bc.sistema.usuario.seguranca.Login;
import bc.sistema.usuario.seguranca.PerguntaSecreta;

/**
 * Classe Professor.
 *
 * @author Felipe Miranda Medeiros
 * @version 1.0
 */
public final class Professor implements Usuario {

    private String nome;
    private final Login login;
    private final Telefone telefonePessoal;
    private final Sala sala;
    private final PerguntaSecreta perguntaSecreta;

    /**
     * Construtor de Professor.
     *
     * @param nome Nome do professor.
     * @param login
     * @param telefonePessoal
     * @param perguntaSecreta
     * @param sala
     * @throws StringVaziaException Se o parametro nome for vazio.
     * @throws NullPointerException Se algum parametro for null.
     */
    public Professor(String nome, Login login, Telefone telefonePessoal,
            PerguntaSecreta perguntaSecreta, Sala sala) throws StringVaziaException,
            NullPointerException {

        if (nome == null) {
            throw new NullPointerException("Parametro nome null");
        }
        if (nome.equals("")) {
            throw new StringVaziaException("Parametro nome vazio");
        }
        if (login == null) {
            throw new NullPointerException("Parametro login null");
        }
        if (telefonePessoal == null) {
            throw new NullPointerException("Parametro telefonePessoal null");
        }
        if (perguntaSecreta == null) {
            throw new NullPointerException("Parametro perguntaSecreta null");
        }
        if (sala == null) {
            throw new NullPointerException("Parametro sala null");
        }

        setNome(nome);
        this.login = login;
        this.perguntaSecreta = perguntaSecreta;
        this.sala = sala;
        this.telefonePessoal = telefonePessoal;
    }

    /**
     * Atribui um número ao telefone.
     *
     * @param numeroTelefone Número do telefone.
     * @throws TelefoneInvalidoException Se o número do telefone for maior que 8
     * dígitos ou menor que isso.
     */
    //Já testado na classe Telefone.
    public void setTelefonePessoal(int numeroTelefone) throws TelefoneInvalidoException {
        telefonePessoal.setTelefone(numeroTelefone);
    }

    /**
     * Retorna o número do telefone.
     *
     * @return O número do telefone.
     */
    //Já testado na classe Telefone.
    public int getTelefonePessoal() {
        return telefonePessoal.getTelefone();
    }

    //Metodos da composição com sala
    /**
     * Atribui um nome a sala.
     *
     * @param sala Nome ou número da sala.
     * @throws SalaInvalidaException Se o nome da sala for null ou vazio.
     */
    //Já testado na classe Sala.
    public void setSala(String sala) throws SalaInvalidaException {
        this.sala.setSala(sala);
    }

    /**
     * Retorna o nome da sala.
     *
     * @return o nome da sala.
     */
    //Já testado na classe Sala.
    public String getSala() {
        return sala.getSala();
    }

    /**
     * Atribiu um nome ao bloco.
     *
     * @param bloco Nome do bloco.
     * @throws SalaInvalidaException Se o nome do bloco for null ou vazio.
     */
    //Já testado na classe Sala.
    public void setNomeDoBloco(String bloco) throws SalaInvalidaException {
        sala.setBloco(bloco);
    }

    /**
     * Retorna o nome do bloco.
     *
     * @return o nome do bloco.
     */
    //Já testado na classe Sala.
    public String getBloco() {
        return sala.getBloco();
    }

    /**
     * Atribui um número ao telefone da sala.
     *
     * @param numeroTelefone Número do telefone.
     * @throws TelefoneInvalidoException Se o número do telefone for maior que 8
     * dígitos ou menor que isso.
     */
    //Já testado na classe Sala.
    public void setTelefoneDaSala(int numeroTelefone) throws TelefoneInvalidoException {
        sala.setTelefone(numeroTelefone);
    }

    /**
     * Retorna o número do telefone da sala.
     *
     * @return o número do telefone da sala.
     */
    //Já testado na classe Sala.
    public int getTelefoneDaSala() {
        return sala.getTelefone();
    }

    /**
     * Retorna o nome do professor.
     *
     * @return nome do professor.
     */
    @Override
    public String getNome() {
        return nome;
    }

    /**
     * Atribui um nome ao professor.
     *
     * @param nome nome do professor.
     * @throws NullPointerException Se o nome for null.
     * @throws StringVaziaException Se o nome for vazio.
     */
    public void setNome(String nome) throws NullPointerException, StringVaziaException {
        if (nome == null) {
            throw new NullPointerException("Parametro nome null");
        }
        if (nome.equals("")) {
            throw new StringVaziaException("Parametro nome vazio");
        }
        this.nome = nome;
    }

    /**
     * Altera a senha caso as senhas passadas sejam válidas e a senha atual
     * corresponda com a que o usuário forneceu.
     *
     * @param senhaAtual Senha atual do usuário.
     * @param novaSenha Nova senha atual do usuário.
     * @throws SenhaInvalidaException Se alguns dos parametros passado forem
     * vazios ou nulos, ou se a senha atual não corresponder a passada.
     */
    //Implementação dos métodos da interface Usuario
    //Já testado na classe Login.
    @Override
    public void redefinirSenha(String novaSenha, String senhaAtual) throws SenhaInvalidaException {
        login.setSenha(senhaAtual, novaSenha);
    }

    /**
     * Altera a senha caso a resposta da pergunta de segurança seja igual a que
     * o usuário passou.
     *
     * @param novaSenha Nova senha que compreende os requisitos mínimos de
     * segurança.
     * @param perguntaSecreta PerguntaSecreta pertecente ao usuário.
     * @param resposta Resposta passada pelo usuário.
     * @throws SenhaInvalidaException Se a nova senha passada for vazia ou nula
     * e ter os requisitos mínimos de segurança.
     * @throws RespostaInvalidaException Se a resposta não compreender a
     * exigencia de pelo menos 5 caracteres ou não for igual a resposta
     * fornecida pelo usuário.
     * @throws NullPointerException Se a pergunta secreta for null.
     */
    //Já testado na classe Login.
    @Override
    public void redefinirSenha(String novaSenha, PerguntaSecreta perguntaSecreta, String resposta)
            throws RespostaInvalidaException, SenhaInvalidaException {
        if (validarResposta(resposta)) {
            login.setSenha(novaSenha, perguntaSecreta, resposta);
        }
    }

    /**
     * Define uma nova pergunta e resposta.
     *
     * @param id Um id da pergunta válido (0-6).
     * @param resposta Uma resposta com 5 ou mais caracteres.
     * @throws IndexOutOfBoundsException Se o id passado não estiver entre 0-6.
     * @throws RespostaInvalidaException Se a resposta não compreender a
     * exigencia de pelo menos 5 caracteres.
     */
    //Já testado na classe PerguntaSecreta.
    @Override
    public void novaPergunta(int id, String resposta) throws IndexOutOfBoundsException, RespostaInvalidaException {
        perguntaSecreta.novaPergunta(id, resposta);
    }

    /**
     * Verifica se dado uma resposta ela é igual à passada pelo usuário.
     *
     * @param resposta Resposta a ser validada.
     * @return True se a reposta passada conferir com a dada pelo usuário no ato
     * do cadastramento, caso contrário retornará False.
     */
    //Já testado na classe PerguntaSecreta.
    @Override
    public boolean validarResposta(String resposta) {
        return perguntaSecreta.validarResposta(resposta);
    }

    /**
     * Verifica se o username e a senha são iguais as criadas pelo usuário.
     *
     * @param username Username a ser validado.
     * @param senha Senha a ser validada.
     * @return True se a senha e o username passados como parametros forem
     * iguais ao que foi criado no momento do cadastro, e False se apenas um
     * deles não forem validados.
     */
    //Já testado na classe Login.
    @Override
    public boolean validarLogin(String username, String senha) {
        return login.validar(username, senha);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || (getClass() != obj.getClass())) {
            return false;
        }
        Professor other = (Professor) obj;
        if (login == null) {
            if (other.login != null) {
                return false;
            }
        } else if (!login.equals(other.login)) {
            return false;
        }
        return true;
    }
}
